ESP32のSecure Bootの仕組み

您所在的位置:网站首页 esp32 secure boot fail 攻击 ESP32のSecure Bootの仕組み

ESP32のSecure Bootの仕組み

2023-09-12 12:03| 来源: 网络整理| 查看: 265

はじめに

Secure Bootについて知りたくて、手元にあったESP32のSecure Bootの仕組みを調べました。実際にやってしまうと元に戻せなくなるので試してはいません。

主に参考にした資料はこちら。 ESP-IDF Programming Guide - Secure Boot 日本語訳も作ってみました。 https://qiita.com/hisashij/items/3372c93ebc28fa4298f9

手順を確認する際に使った環境はESP-IDF v4.0.1。バージョンが異なるとmenuconfigの構成が少し変わるようです。

前提情報 ESP32の基本的なbootの流れ まずROMにある1st-stage bootloaderが、フラッシュのオフセット0x1000から2nd-stage bootloaderをRAMに読み込み、処理を渡す。 2nd-stage bootloaderが、フラッシュからパーティションテーブルとアプリイメージをRAMに読み込み、アプリに処理を渡す。

image.png

ESP32のSecureBootの流れ(概要)

image.png

ESP32のSecure Bootで使われる鍵

以下2つの鍵を使用する。

Secure Boot Key

AES 256bit ROMにある1st-stage bootloaderが、2nd-stage bootloaderをフラッシュから読み込んだ際の検証(ダイジェスト値の計算)で使われる。 最初にブートされた際にhardware secure boot supportが生成し、eFuseのBLOCK 2に焼きこまれる。当該領域はR/W Protectされており読み出し不可。

Secure Boot Signing Key

ECDSA 256bit 2nd-stage bootloaderが、パーティションテーブルとアプリイメージをフラッシュから読み込んだ際の署名検証で使われる。 鍵は開発者がビルド前に生成し、厳重に保管しておく。ビルド時にその鍵を使って署名が行われる。検証用の公開鍵は2nd-stage bootloaderに埋め込まれる。

image.png

ESP32のeFuse eFuseとは、一度ビットを1にすると0に戻すことができないメモリ。 ESP32は、各256ビットのBLOCKが、0から3まである。 ESP32のSecure Bootの種類

大きく以下3つの方式がある。

Secure Boot: One-Time Flash 本番環境で使う基本的な方式。一度書き込んだ2nd-stage bootloaderは、hardware内で生成されeFuseに焼きこまれたSecure Boot Keyで保護されており、変更できない。

Secure Boot: Reflashable 2nd-stage bootloaderを後で変更できる方式。Secure Boot Keyは、hardware内で生成されたものではなく、Secure Boot Signing Keyから導出されたものを使う。

Signed App Verification Without Hardware Secure Boot 2nd-stage bootloaderの検証は行わず、アプリイメージの署名検証だけを行う方式。

One-Time Flash方式

この手順を行うと元に戻せなくなるのでご注意ください。

ビルドの流れ

menuconfigでの設定。 「Security features」->「Enable hardware secure boot in bootloader」にチェックを入れる。デフォルトで「Secure bootloader mode」には「One-time flash」が選択されている。

Secure Boot Signing Keyを生成する。 python espsecure.py generate_signing_key secure_boot_signing_key.pem

2nd-stage bootloaderをビルドする。 idf.py bootloader これにより、セキュアブートサポートが有効化され、Secure Boot Signing Keyに対応する公開鍵が含まれた、2nd-stage bootloaderが作られる。

2nd-stage bootloaderをフラッシュへ書き込む。 idf.py -p (PORT) bootloader-flash

アプリをビルドする。 idf.py build アプリはSecure Boot Signing Keyで署名される。

アプリをフラッシュへ書き込む。 idf.py -p (PORT) flash

初回ブート時の流れ まずROMにある1st-stage bootloaderが、フラッシュのオフセット0x1000から2nd-stage bootloaderをRAMに読み込む。 hardware secure boot supportが、Secure Boot Key(AES-256鍵)を生成してeFuse BLOCK 2に焼きこむ。 hardware secure boot supportが、2nd-stage bootloaderのSHA-512ダイジェスト(64バイト)を計算し、計算に使用したIV(128バイト)とともに、フラッシュのオフセット0x0000に書き込む。ダイジェストの計算は以下の通り。 ランダムに生成したIVを2nd-stage bootloaderの先頭に連結。 AES-256で暗号化。 SHA-512でダイジェストを計算。 hardware secure boot supportが、セキュアブートの各種設定をeFuse BLOCK 0に焼きこむともに、BLOCK 0のabstract_done_0 bitを立てることでセキュアブートを有効化し、2nd-stage bootloaderに処理を渡す。 2nd-stage bootloaderは、フラッシュからパーティションテーブルとアプリイメージをRAMに読み込む。 2nd-stage bootloaderは、自身に組み込まれている署名検証用公開鍵(ECDSA 256bit)を使って、これらの検証を行った後、アプリに処理を渡す。 2度目以降のブート時の流れ まずROMにある1st-stage bootloaderが、フラッシュのオフセット0x1000から2nd-stage bootloaderをRAMに読み込む。 eFuse BLOCK 0のabstract_done_0 bitが立っていたらSecure Bootの処理を開始。hardware secure boot supportを使って以下の流れで2nd-stage bootloaderを検証する。 フラッシュのオフセット0x0000から、128バイトのIVと、64バイトのSHA-512ダイジェストデータを読み込む。 eFuse BLOCK 2からAES-256鍵を読み込んで、2nd-stage bootloaderのダイジェストを再計算する。ダイジェストの計算は以下の通り。 2nd-stage bootloaderの先頭にIVを連結。 AES-256で暗号化。 SHA-512でダイジェストを計算。 再計算されたダイジェストと、フラッシュ読み込んだダイジェストが一致していることを確認。 2nd-stage bootloaderが検証されたら、2nd-stage bootloaderに処理を渡す。 2nd-stage bootloaderは、フラッシュからパーティションテーブルとアプリイメージをRAMに読み込む。 2nd-stage bootloaderは、自身に組み込まれている署名検証用公開鍵(ECDSA 256bit)を使って、これらの検証を行った後、アプリに処理を渡す。 アプリ置き換え時の流れ

同じSecure Boot Signing Keyがある状態で以下を行えばアプリが置き換えられる(たぶん)。

アプリをビルドする。 idf.py build アプリはSecure Boot Signing Keyで署名される。

アプリをフラッシュへ書き込む。 idf.py -p (PORT) flash

Reflashable方式

この手順を行うと元に戻せなくなるのでご注意ください。

ビルドの流れ

menuconfigでの設定。 「Security features」->「Enable hardware secure boot in bootloader」にチェックを入れる。 続いて「Secure bootloader mode」を「One-time flash」から「Reflashable」に変更する。

Secure Boot Signing Keyを生成する。 python espsecure.py generate_signing_key secure_boot_signing_key.pem

2nd-stage bootloaderをビルドする。 idf.py bootloader これにより、セキュアブートサポートが有効化され、Secure Boot Signing Keyに対応する公開鍵が含まれた、2nd-stage bootloaderが作られる。また、Secure Boot Signing Keyから導出したSecure Boot Keyが作られる。

Secure Boot KeyをeFuseへ書き込む。 ビルド時に表示されるメッセージにしたがって以下のようなコマンドで書き込む。 python.exe espefuse.py burn_key secure_boot secure-bootloader-key-256.bin

2nd-stage bootloaderをフラッシュへ書き込む。 idf.py -p (PORT) bootloader-flash

アプリをビルドする。 idf.py build アプリはSecure Boot Signing Keyで署名される。

アプリをフラッシュへ書き込む。 idf.py -p (PORT) flash

初回ブート時の流れ

One-Time Flash方式と同じ。ただし、Secure Boot KeyはeFuseに書込み済のものを使用する。

2度目以降のブート時の流れ

One-Time Flash方式と同じ。

2nd-stage bootloader置き換え時の流れ

同じSecure Boot Signing Keyがある状態で以下を行えばbootloaderとアプリが置き換えられる(たぶん)。

2nd-stage bootloaderをビルドする。 idf.py bootloader

2nd-stage bootloaderのダイジェスト値をフラッシュへ書き込む。 ビルド時に表示されるメッセージにしたがって以下のようなコマンドで書き込む。 python.exe esptool.py --chip esp32 --port (PORT) --baud (BAUD) --before default_reset --after no_reset write_flash --flash_mode dio --flash_freq 40m --flash_size 2MB -u 0x0 bootloader-reflash-digest.bin

2nd-stage bootloaderをフラッシュへ書き込む。 idf.py -p (PORT) bootloader-flash

アプリをビルドする。 idf.py build アプリはSecure Boot Signing Keyで署名される。

アプリをフラッシュへ書き込む。 idf.py -p (PORT) flash

Signed App Verification Without Hardware Secure Boot方式 ビルドの流れ

menuconfigでの設定。 「Security features」->「Require signed app amages」にチェックを入れる。チェックを入れると表示される、「Bootloader verifies app signatures」「Verify app signature on update」に必要に応じてチェックを入れる。

Secure Boot Signing Keyを生成する。 python espsecure.py generate_signing_key secure_boot_signing_key.pem

アプリをビルドする。 idf.py build アプリはSecure Boot Signing Keyで署名される。

アプリをフラッシュへ書き込む。 idf.py -p (PORT) flash

ブート時の流れ まずROMにある1st-stage bootloaderが、フラッシュのオフセット0x1000から2nd-stage bootloaderをRAMに読み込んで処理を渡す。 2nd-stage bootloaderは、フラッシュからパーティションテーブルとアプリイメージをRAMに読み込む。 2nd-stage bootloaderは、自身に組み込まれている署名検証用公開鍵(ECDSA 256bit)を使って、これらの検証を行った後、アプリに処理を渡す。 アプリ置き換え時の流れ

同じSecure Boot Signing Keyがある状態で以下を行えばアプリが置き換えられる(たぶん)。

アプリをビルドする。 idf.py build アプリはSecure Boot Signing Keyで署名される。

アプリをフラッシュへ書き込む。 idf.py -p (PORT) flash



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3